package com.hitqz.robot.biz.listener;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.base.Objects;
import com.hitqz.robot.api.business.enums.RobotModelEnum;
import com.hitqz.robot.api.business.enums.TicketsStatusEnum;
import com.hitqz.robot.api.business.enums.WorkStatusEnum;
import com.hitqz.robot.api.business.event.EquipmentPoseUpdateEvent;
import com.hitqz.robot.api.common.dto.robot.RobotOnlineEventDto;
import com.hitqz.robot.api.common.dto.tickets.CtrlTicketsEvent;
import com.hitqz.robot.api.common.dto.warning.AddWarningDto;
import com.hitqz.robot.api.common.entity.*;
import com.hitqz.robot.api.dispatch.protocol.dto.RobotWarningDto;
import com.hitqz.robot.biz.flow.util.LiteFlowUtil;
import com.hitqz.robot.biz.service.*;
import com.hitqz.robot.camera.EquipmentFactory;
import com.hitqz.robot.camera.IEquipmentService;
import com.hitqz.robot.camera.dto.EquipmentLoginParamsDto;
import com.hitqz.robot.camera.dto.QueryParamsDto;
import com.hitqz.robot.driver.parent.RobotDriverService;
import com.hitqz.robot.netty.NettyClient;
import com.hitqz.robot.netty.service.Send2ServerService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;

/**
 *
 * @author xupkun
 * @date 2024/7/8
 */
@Component
@AllArgsConstructor
@Slf4j
public class RobotEventListener {

    private final RobotDriverService robotDriverService;

    private final RobotService robotService;

    private final SysWarningService sysWarningService;

    private final Send2ServerService send2ServerService;


    private final ExecutorService customThreadPool;

    private final RobotMapService robotMapService;

    private final RobotMapPosService robotMapPosService;

    private final MapAreaService mapAreaService;

    private final RobotEquipmentService robotEquipmentService;

    private final EquipmentFactory equipmentFactory;

    private final TicketsService ticketsService;

    private final RobotEquipmentPoseService robotEquipmentPoseService;


    @Async("poolTaskExecutor")
    @EventListener
    public void onListenerRobotStatus(RobotOnlineEventDto robotOnlineEventDto) {
        Robot robot = robotService.getDefaultRobot();
        if (robotOnlineEventDto.getOnlineStatus() != null) {
            robot.setOnlineStatus(String.valueOf(robotOnlineEventDto.getOnlineStatus()));
        }
        if (StrUtil.isNotBlank(robotOnlineEventDto.getWorkStatus())) {
            log.info("wonListenerRobotStatus" + robotOnlineEventDto.getWorkStatus());
            robot.setWorkStatus(robotOnlineEventDto.getWorkStatus());
        }
        if (robotOnlineEventDto.getOnlineStatus() != null && robotOnlineEventDto.getOnlineStatus().equals("1")) {
            // 机器人上线处理






        }
        robotService.updateById(robot);
    }


    @Async("poolTaskExecutor")
    @EventListener
    public void onListenerWarnings(AddWarningDto addWarningDto) {
        synchronized (addWarningDto.getTitle().intern()) {
            Robot robot = robotService.getDefaultRobot();
            SysWarning sysWarning = sysWarningService.getOne(Wrappers.<SysWarning>lambdaQuery()
                    .eq(SysWarning::getTitle, addWarningDto.getTitle())
                    .eq(StrUtil.isNotBlank(addWarningDto.getCode()) && !Objects.equal(addWarningDto.getCode(),"0"),SysWarning::getCode,addWarningDto.getCode())
                    .eq(SysWarning::getStatus, 0).last("limit 1").orderByDesc(SysWarning::getWarningTime)
            );
            long current = System.currentTimeMillis();
            if (sysWarning != null && (current - sysWarning.getWarningTime().getTime() < (10 *1000))) {
                return;
            }
            SysWarning addWarning = new SysWarning();
            addWarning.setTitle(addWarningDto.getTitle());
            addWarning.setCode(addWarningDto.getCode());
            addWarning.setRobotSn(robot.getRobotSn());
            addWarning.setRobotName(robot.getRobotName());
            addWarning.setWarningObj(robot.getRobotName() + ":" + addWarningDto.getTitle());
            addWarning.setWarningTime(new Date());
            addWarning.setContent(addWarningDto.getContent());
            addWarning.setStatus(0);
            addWarning.setLevel(addWarningDto.getLevel());
            addWarning.setSuggest(addWarningDto.getSuggestion());
            addWarning.setPaths(addWarningDto.getPaths());
            sysWarningService.save(addWarning);
            // 上报
            RobotWarningDto robotWarningDto = new RobotWarningDto();
            BeanUtil.copyProperties(addWarning, robotWarningDto);
            send2ServerService.syncSysWarning(robot, robotWarningDto);
            if (addWarningDto.isStopTask()) {
                // 停止任务
                CtrlTicketsEvent ctrlTicketsEvent = new CtrlTicketsEvent();
                ctrlTicketsEvent.setType(CtrlTicketsEvent.TYPE_STOP);
                ctrlTicketsEvent.setMessage("发生报警，停止任务");
                ctrlTicketsEvent.setTicketsId(LiteFlowUtil.ticketsId);
                SpringUtil.getApplicationContext().publishEvent(ctrlTicketsEvent);
                // 暂停导航等功能
                robotDriverService.motionAbort();
                //


            }
        }
    }

    @EventListener
    @Async("poolTaskExecutor")
    public void onListenerTickets(CtrlTicketsEvent event) {
        Integer type = Optional.ofNullable(event.getType()).orElse(-1);
        Integer ticketsId = event.getTicketsId();
        Tickets tickets = new Tickets();
        if (ticketsId!=null) {
            tickets = ticketsService.getById(ticketsId);
        }
        String typeStr = "";
        Robot robot = robotService.getDefaultRobot();
        switch (type){
            case CtrlTicketsEvent.TYPE_PAUSE->{
                typeStr = "暂停";
                if (Objects.equal(robot.getWorkStatus(),WorkStatusEnum.WORK.getCode())) {
                    log.info("任务暂停设置空闲状态");
                    robot.setWorkStatus(WorkStatusEnum.FREE.getCode());
                    robotService.updateById(robot);
                }
                //中断任务流程
                LiteFlowUtil.setInterruptFlag();
                //停止机器人运动
                robotDriverService.motionAbort();
                //修改工单状态
                if (Objects.equal(tickets.getStatus(),TicketsStatusEnum.STATUS_EXECUTING.getCode())) {
                    tickets.setStatus(TicketsStatusEnum.STATUS_PAUSED.getCode());
                }
            }
            case CtrlTicketsEvent.TYPE_STOP->{
                typeStr = "终止";
                if (Objects.equal(robot.getWorkStatus(),WorkStatusEnum.WORK.getCode())) {
                    log.info("任务终止设置空闲状态");
                    robot.setWorkStatus(WorkStatusEnum.FREE.getCode());
                    robotService.updateById(robot);
                }
                //中断任务流程
                LiteFlowUtil.setInterruptFlag();
                //停止机器人运动
                robotDriverService.motionAbort();
                //停止外设运动
                customThreadPool.submit(()->{
                    List<RobotEquipment> equipments = robotEquipmentService.list(Wrappers.<RobotEquipment>lambdaQuery().eq(RobotEquipment::getIsRecordParam, 1));
                    for (RobotEquipment equipment : CollUtil.emptyIfNull(equipments)) {
                        IEquipmentService service = equipmentFactory.getServiceByBrand(equipment.getBrand());
                        if (service==null){
                            continue;
                        }
                        QueryParamsDto queryParamsDto = new QueryParamsDto();
                        queryParamsDto.setIp(equipment.getIp());
                        queryParamsDto.setUsername(equipment.getUsername());
                        queryParamsDto.setPassword(equipment.getPassword());
                        queryParamsDto.setPort(equipment.getPort());
                        queryParamsDto.setChannel(equipment.getChannel());
                        service.motionAbort(queryParamsDto);
                    }
                });
                //修改工单状态
                if (Objects.equal(tickets.getStatus(),TicketsStatusEnum.STATUS_EXECUTING.getCode())) {
                    tickets.setStatus(TicketsStatusEnum.STATUS_STOP.getCode());
                }
            }
            case CtrlTicketsEvent.TYPE_RESUME -> {
                typeStr = "恢复";
                if (Objects.equal(tickets.getStatus(),TicketsStatusEnum.STATUS_PAUSED.getCode())) {
                    tickets.setStatus(TicketsStatusEnum.STATUS_EXECUTING.getCode());
                }
            }
        }
        //更新工单状态
        if (tickets.getId()!=null) {
            ticketsService.updateById(tickets);
        }
        log.info("[event]ctrl tickets:{},type:{},reason:{}",event.getTicketsId(),typeStr,event.getMessage());
    }

    @EventListener
    public void onListenerRobot(Robot robot) {
        try {
            log.info("加载机器人模型:" + RobotModelEnum.CMD_ROBOT_MODEL.get(robot.getRobotModel().toLowerCase()));
            CompletableFuture.runAsync(() -> {
                try {
                    // 连接服务端
                    Integer isStandAlone = Optional.of(robot).map(Robot::getIsStandAlone).orElse(0);
                    if (Objects.equal(isStandAlone, 1)) {
                        log.warn("单机运行,不连接服务器");
                        NettyClient.getInstance().shutdown();
                        return;
                    }
                    String host = robot.getServerAddress();
                    int port = 9874;
                    if (robot.getServerAddress().contains(":")) {
                        host = robot.getServerAddress().split(":")[0];
                        port = Integer.parseInt(robot.getServerAddress().split(":")[1]);
                    }
                    if (StrUtil.isNotEmpty(robot.getServerAddress())) {
                        NettyClient.getInstance().connect(robot.getRobotSn(), host, port);
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }, customThreadPool);
            CompletableFuture.runAsync(() -> {
                log.info("机器人driver[{}]", robotDriverService.getClass().getName());
                robotDriverService.doOnlineMode(robot);
            }, customThreadPool);
            //选择地图
            CompletableFuture.runAsync(() -> {
                String mapCode = robot.getMapCode();
                RobotMap map = robotMapService.findByMapCode(mapCode);
                List<RobotMapPos> list = robotMapPosService.list(Wrappers.<RobotMapPos>lambdaQuery().eq(RobotMapPos::getMapCode, mapCode));
                map.setPosList(list);
                robotDriverService.selMap(map);
            }, customThreadPool);
            CompletableFuture.runAsync(mapAreaService::initMapArea, customThreadPool);
            //初始化外设
            CompletableFuture.runAsync(() -> {
                //相机
                List<RobotEquipment> list = robotEquipmentService.list();
                for (RobotEquipment equipment : CollUtil.emptyIfNull(list)) {
                    try {
                        IEquipmentService service = equipmentFactory.getServiceByBrand(equipment.getBrand());
                        if (service != null) {
                            EquipmentLoginParamsDto loginParamsDto = new EquipmentLoginParamsDto();
                            loginParamsDto.setUsername(equipment.getUsername());
                            loginParamsDto.setPort(equipment.getPort());
                            loginParamsDto.setPassword(equipment.getPassword());
                            loginParamsDto.setIp(equipment.getIp());
                            service.login(loginParamsDto);
                        } else {
                            log.info("{} not sdk,not init {} ", equipment.getName(), equipment.getBrand());
                        }
                        Thread.sleep(200);
                    } catch (Exception e) {
                        log.error("初始化外设失败", e);
                    }
                }
            }, customThreadPool);
            // 自定义外设姿态
            CompletableFuture.runAsync(()->{
                List<RobotEquipment> equipments = robotEquipmentService.list();
                for (RobotEquipment equipment : CollUtil.emptyIfNull(equipments)) {
                    List<RobotEquipmentPose> poseList = robotEquipmentPoseService.list(Wrappers.<RobotEquipmentPose>lambdaQuery()
                            .eq(RobotEquipmentPose::getEquipmentId, equipment.getId()));
                    if (poseList.isEmpty()){
                        continue;
                    }
                    EquipmentPoseUpdateEvent updateEvent = EquipmentPoseUpdateEvent.builder().ip(equipment.getIp()).brand(equipment.getBrand()).poseList(poseList).build();
                    SpringUtil.getApplicationContext().publishEvent(updateEvent);
                }
            }, customThreadPool);
        }catch (Exception e){
            log.error("初始化错误" + e);
        }
    }


}
